/**
 * @file display.c
 * @brief COSC361 - MCU Jukebox Project\n
 * Group: Hamish Cumming, Brian Thorne\n
 * Latest source can be obtained using SVN from google's code repository with the following command:\n
 * svn checkout http://mega8-hob.googlecode.com/svn/trunk/ jukebox-hamish-brian\n
 * Description: Code for the 7 segment display module\n
 * Date: 25/5/2008
 */
#include "display.h"
#include "Board.h"

/* contains the current status of the 7segment display */
static int digits[2][NUM_DIGITS] = {{0, 0, 0, 0},{LED1, LED2, LED3 , LED4}};
/* A font table for a 7 segment display with the numbers 1-9 */
const static int font[10] = {(LEDa | LEDb | LEDc | LEDd | LEDe | LEDf),
                    (LEDb | LEDc),
                    (LEDa | LEDb | LEDg | LEDe | LEDd),
                    (LEDa | LEDb | LEDg | LEDc | LEDd),
                    (LEDf | LEDg | LEDb | LEDc),
                    (LEDa | LEDf | LEDg | LEDc | LEDd),
                    (LEDa | LEDf | LEDg | LEDc | LEDe | LEDd),
                    (LEDa | LEDb | LEDc),
                    (LEDa | LEDb | LEDc | LEDd | LEDe | LEDf | LEDg),
                    (LEDa | LEDb | LEDc | LEDd | LEDf | LEDg)};

/**
 * @brief Sets the digit in a column (0-3)
 * @param digit Which digit to set
 * @param number The number...
 * @param decimal whether to include the decimal or not
 */
void setDigit(int digit, int number, int decimal)
{
    if (number > 9) return;
    if (digit >= NUM_DIGITS) return;
    //digits[0][digit] = font[number];
    digits[0][digit] = (decimal) ?  font[number] | LEDdp : font[number];
}

/**
 * @brief Displays a number from 0 to 9999
 * @param i The number to display
 */
void displayNumber(unsigned int i)
{
    //save a few clocks
    static unsigned int prev = 0;
    if (i == prev) return;
    prev = i;
    
    if (i > 9999) i = 0; //only got four digits
    
    int dig[4];
    dig[0] = i/1000;
    dig[1] = (i % 1000)/100;
    dig[2] = (i % 100)/10;
    dig[3] = i % 10;
    int j;
    for(j=0; j<4; j++) setDigit(j,dig[j],0);
}

/**
 * @brief Similar to display number, but in minutes and seconds
 */
void displayTime(unsigned int i)
{
    //save a few clocks
    static unsigned int prev = 0;
    if (i == prev) return;
    prev = i;
    
    if (i > 9999) i = 0; //only got four digits
    
    int dig[4];
    int minutes = i / 60;
    int seconds = i % 60;
    dig[0] = (minutes % 100)/10;
    dig[1] = minutes % 10;
    dig[2] = (seconds % 100)/10;
    dig[3] = seconds % 10;
    int j;
    for(j=0; j<4; j++) setDigit(j,dig[j], (j==1) ? 1 : 0);
    
}


/**
 * @brief Updates a digit on the display
 * @param digit The digit to update (0-3, 0 is closest to the top end fo the board)
 */
void led_update(int digit)
{
    if (digit > NUM_DIGITS) return;
    AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, LED_ALLDIGITS);
    AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED_ALLSEGS);
    AT91F_PIO_SetOutput( AT91C_BASE_PIOA, digits[1][digit]);
    AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, digits[0][digit]);
}

/**
 * @brief Initialise the display
 */
void display_init()
{
    //configure the LEDs for output
    AT91F_PIO_CfgOutput( AT91C_BASE_PIOA, LED_ALLDIGITS | LED_ALLSEGS);
    //clear all LED segments
    AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED_ALLSEGS);
    //clear all LED digits
    AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, LED_ALLDIGITS);
    
    /* Set all digits to 0 on the display */
    unsigned int i = 0;
    while(i<4){setDigit(i,0,0);i++;}
}
